#include "compat/queue.h"
#include "event-internal.h"
#include "include/event_struct.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

// 各类事件种类
#define EV_TIMEOUT 0x01 // 定时事件
#define EV_READ 0x02    // 可读事件
#define EV_WRITE 0x04   // 可写事件
#define EV_SIGNAL 0x08  // 信号事件
#define EV_PERSIST 0x10 // 永久事件
#define EV_ET 0x20      // 延边触发事件

#define MICROSECONDS_MASK COMMON_TIMEOUT_MICROSECONDS_MASK
#define COMMON_TIMEOUT_IDX_MASK 0x0ff00000
#define COMMON_TIMEOUT_IDX_SHIFT 20
#define COMMON_TIMEOUT_MASK 0xf0000000
#define COMMON_TIMEOUT_MAGIC 0x50000000

#define COMMON_TIMEOUT_IDX(tv) (((tv)->tv_usec & COMMON_TIMEOUT_IDX_MASK) >> COMMON_TIMEOUT_IDX_SHIFT)

static void event_queue_remove(struct event_base *base, struct event *ev, int queue);
static void event_queue_insert(struct event_base *base, struct event *ev, int queue);
static inline int is_common_timeout(const struct timeval *tv, const struct event_base *base);
static inline struct common_timeout_list *get_common_timeout_list(struct event_base *base, const struct timeval *tv);
static int gettime(struct event_base *base, struct timeval *tp);
static void insert_common_timeout_inorder(struct common_timeout_list *ctl, struct event *ev);
static void common_timeout_schedule(struct common_timeout_list *ctl, const struct timeval *now, struct event *head);

//  添加注册事件
static inline int event_add_internal(struct event *ev, const struct timeval *tv, int tv_is_absolute)
{
    struct event_base *base = ev->ev_base;
    int res = 0;
    int notify = 0;
    // 它奶奶的 先不做锁了
    // TODO

    /*新添加的事件处理器是定时器 为它在时间堆上留一个位置 */

    // 新添加的事件处理器是定时器 还没有被添加到通用定时器队列或者时间堆中 为这个定时器在时间
    // 堆上留一个位置
    if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT))
    {
        if (min_heap_reserve(&base->timeheap, 1 + min_heap_size(&base->timeheap)) == -1)
            return -1;
    }
    /* 当前的事件是io信号事件 没有被注册和激活 */
    // 如果当前事件是io事件或者信号事件 并且没有被激活没有被注册
    if ((ev->ev_events & (EV_READ | EV_WRITE | EV_SIGNAL)) && !(ev->ev_flags & (EVLIST_INSERTED | EVLIST_ACTIVE)))
    {
        if (ev->ev_events & (EV_READ | EV_WRITE)) // 读事件或者写事件
        {
            // 添加IO事件和io事件处理器之间的关系
            res = evmap_io_add(base, ev->ev_fd, ev);
        }
        else if (ev->ev_events & (EV_SIGNAL))
        {
            // 添加信号事件和信号处理器之间的关系
            res = evmap_signal_add(base, (int)ev->ev_fd, ev);
        }
        if (res != -1)
        {
            // 映射添加成功了
            // 将事件插入注册事件队列
            event_queue_insert(base, ev, EVLIST_INSERTED);
        }
        if (res == 1)
        {
            notify = 1;
            res = 0;
        }
    }

    /* 将事件添加到通用定时器或者事件堆中(定时器事件或者io信号事件(根据函数的结果决定)) */

    // 下面将事件处理器添加到通用定时器或者时间堆中，
    // 对于信号事件处理器和io事件处理器。根据evmap_*_add函数的结果
    // 来决定是否添加(为事件设置超时)；对于定时器 始终添加
    if (res != -1 && tv != NULL)
    {
        struct timeval now;
        int common_timeout;
        // 对于永久性事件处理器 如果超时事件不是绝对事件 就要将该超时处理器的
        // 超时事件记录进ev->ev_io_timeout中（更新超时事件）
        if (ev->ev_closure == EV_CLOSURE_PERSIST && !tv_is_absolute)
        {
            ev->ev_io_timeout = *tv;
            // 该事件处理器已经被插入通用定时器队列或者事件堆就先删除
            if (ev->ev_flags & EVLIST_TIMEOUT) // 在时间队列里
            {
                if (min_heap_elt_is_top(ev))
                {
                    notify = 1;
                }
                event_queue_remove(base, ev, EVLIST_TIMEOUT);
            }
            // 如果待添加的事件处理器已经被激活 原因是超时，则从活动事件队列中删除它 以避免其回调函数被执行
            // 对于信号事件处理器 必要时还需要将其ncalls成员设置为0 信号被触发时将指定其回调函数被调用的此时 将
            // ncalls设置为0 将有效洗净的终止信号事件的处理
            if ((ev->ev_flags & EVLIST_ACTIVE) && (ev->ev_res & EV_TIMEOUT))
            {
                if (ev->ev_events & EV_SIGNAL)
                {
                    // 如果这两个属性存在
                    if (ev->ev_ncalls && ev->ev_pncalls)
                    {
                        *ev->ev_pncalls = 0; // 将其置0
                    }
                }
                event_queue_remove(base, ev, EVLIST_ACTIVE);
            }

            gettime(base, &now);
            common_timeout = is_common_timeout(tv, base);
            if (tv_is_absolute)
            {
                ev->ev_timeout = *tv;
            } // 判断是插入定时器队列还是插入事件堆
            else if (common_timeout)
            {
                struct timeval tmp = *tv;
                tmp.tv_usec &= MICROSECONDS_MASK;
                evutil_timeradd(&now, &tmp, &ev->ev_timeout);
                ev->ev_timeout.tv_usec |= (tv->tv_usec & ~MICROSECONDS_MASK);
            }
            else
            {
                // 加上当前系统时间，取得定时器超时的绝对时间
                evutil_timeradd(&now, tv, &ev->ev_timeout);
            }

            // 最后插入定时器
            event_queue_insert(base, ev, EVLIST_TIMEOUT);
            // 如果插入的事件处理器是通用定时器队列中的第一个元素
            // 通过common_timeout_schedule将其转移到时间堆中 这样通用定时器和时间堆就得到了
            // 统一的处理
            if (common_timeout)
            {
                struct common_timeout_list *ctl = get_common_timeout_list(base, &ev->ev_timeout);
                // 是队列中的第一个事务
                if (ev == TAILQ_FIRST(&ctl->events))
                {
                    common_timeout_schedule(ctl, &now, ev);
                }
            }
            else
            {
                if (min_heap_elt_is_top(ev))
                    notify = 1;
            }
        }
    }
    return res;
}


// 将事件从某个队列中移除
static void event_queue_remove(struct event_base *base, struct event *ev, int queue)
{
    // 这里要放锁 // 此事件库不做锁了 告辞
    // 如果该事件不在这个队列中
    if (!(ev->ev_flags & queue))
    {
        // 在这里报告事件不在队列中
        return;
    }
    // 该事件不在内部事件队列中 则事件计数-1
    if (~ev->ev_flags & EVLIST_INTERNAL)
        base->event_count--;
    // 将事件标志中这件在这个队列中的标志取消
    ev->ev_flags &= ~queue;
    // 各个队列的操作不同
    switch (queue)
    {
    case EVLIST_INSERTED:
        TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
        break;
    case EVLIST_ACTIVE:
        base->event_count_active--;
        TAILQ_REMOVE(&(base->activequeues)[ev->ev_pri], ev, ev_active_next);
        break;
    case EVLIST_TIMEOUT:
        if (is_common_timeout(&ev->ev_timeout, base))
        {
            // 从通用时间队列中的队列中删除
            struct common_timeout_list *ctl = get_common_timeout_list(base, &ev->ev_timeout);
            TAILQ_REMOVE(&ctl->events, ev, ev_timeout_pos.ev_next_with_common_timeout);
        }
        else
        { // 从时间最小堆中删除
            min_heap_erase(&base->timeheap, ev);
        }
        break;
    default:
        printf("unknow queue");
    }
}

static void event_queue_insert(struct event_base *base, struct event *ev, int queue)
{
    // 如果该事件已经在该队列中了
    if (ev->ev_flags & queue)
    {
        /* Double insertion is possible for active events */
        if (queue & EVLIST_ACTIVE)
            return;
        // 直接返回
        return;
    }
    // 如果这个事件不在内部 则base所拥有事件数量++
    if (~ev->ev_flags & EVLIST_INTERNAL)
        base->event_count++;
    // 给该事件添加这个队列标志
    ev->ev_flags |= queue;
    switch (queue)
    {
    case EVLIST_INSERTED:
        TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
        break;
    case EVLIST_ACTIVE:
        base->event_count_active++;
        TAILQ_INSERT_TAIL(&base->activequeues[ev->ev_pri], ev, ev_active_next);
        break;
    // 定时事件队列最为复杂
    case EVLIST_TIMEOUT: {
        // 在这里插入定时事件的通用定时队列
        if (is_common_timeout(&ev->ev_timeout, base))
        {
            // 将ev 事件插入通用定时队列中
            struct common_timeout_list *ctl = get_common_timeout_list(base, &ev->ev_timeout);
            insert_common_timeout_inorder(ctl, ev);
        }
        else
            // 此处插入定时事件最小堆中
            min_heap_push(&base->timeheap, ev);
        break;
    }
    default:
        printf("unknow queue");
    }
}
// 简单版假设都进入时间堆中
static inline int is_common_timeout(const struct timeval *tv, const struct event_base *base)
{
    // int idx;
    // if ((tv->tv_usec & COMMON_TIMEOUT_MASK) != COMMON_TIMEOUT_MAGIC)
    //     return 0;
    // idx = COMMON_TIMEOUT_IDX(tv);
    // return idx < base->n_common_timeouts;

    return 0;
}

static inline struct common_timeout_list *get_common_timeout_list(struct event_base *base, const struct timeval *tv)
{
    // 将时间戳转化为index
    return base->common_timeout_queues[COMMON_TIMEOUT_IDX(tv)];
}
static int gettime(struct event_base *base, struct timeval *tp)
{

    if (base->tv_cache.tv_sec)
    {
        *tp = base->tv_cache;
        return (0);
    }

#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
    if (use_monotonic)
    {
        struct timespec ts;
        if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
            return (-1);
        tp->tv_sec = ts.tv_sec;
        tp->tv_usec = ts.tv_nsec / 1000;
        if (base->last_updated_clock_diff + CLOCK_SYNC_INTERVAL < ts.tv_sec)
        {
            struct timeval tv;
            evutil_gettimeofday(&tv, NULL);
            evutil_timersub(&tv, tp, &base->tv_clock_diff);
            base->last_updated_clock_diff = ts.tv_sec;
        }
        return (0);
    }
#endif
    return (evutil_gettimeofday(tp, NULL));
}

// 将ev 插入通用定时队列
static void insert_common_timeout_inorder(struct common_timeout_list *ctl, struct event *ev)
{
    // 获取事件ev
    struct event *e;
    // TODO
    TAILQ_FOREACH_REVERSE(e, &ctl->events, event_list, ev_timeout_pos.ev_next_with_common_timeout)
    {
        // 如果
        if (evutil_timercmp(&ev->ev_timeout, &e->ev_timeout, >=))
        {
            TAILQ_INSERT_AFTER(&ctl->events, e, ev, ev_timeout_pos.ev_next_with_common_timeout);
            return;
        }
    }
    TAILQ_INSERT_HEAD(&ctl->events, ev, ev_timeout_pos.ev_next_with_common_timeout);
}
// 将通用时间队列中的事件移动到最小堆中
static void common_timeout_schedule(struct common_timeout_list *ctl, const struct timeval *now, struct event *head)
{
    // 获取当前 时间
    struct timeval timeout = head->ev_timeout;
    timeout.tv_usec &= MICROSECONDS_MASK;
    // 重新注册事件
    event_add_internal(&ctl->timeout_event, &timeout, 1);
}